Türkçe

TypeScript namespace birleştirmenin gücünü keşfedin! Bu kılavuz, modülerlik, genişletilebilirlik ve daha temiz kod için gelişmiş modül bildirim desenlerini, küresel TypeScript geliştiricileri için pratik örneklerle inceliyor.

TypeScript Namespace Birleştirme: Gelişmiş Modül Bildirim Desenleri

TypeScript, kodunuzu yapılandırmak ve organize etmek için güçlü özellikler sunar. Bu özelliklerden biri, aynı ada sahip birden fazla namespace tanımlamanıza olanak tanıyan ve TypeScript'in bu bildirimleri otomatik olarak tek bir namespace altında birleştirdiği namespace birleştirmedir. Bu yetenek, mevcut kütüphaneleri genişletmek, modüler uygulamalar oluşturmak ve karmaşık tür tanımlarını yönetmek için özellikle kullanışlıdır. Bu kılavuz, namespace birleştirmeyi kullanmak için gelişmiş desenleri derinlemesine inceleyecek ve daha temiz, daha sürdürülebilir TypeScript kodu yazmanızı sağlayacaktır.

Namespace'leri ve Modülleri Anlamak

Namespace birleştirmeye dalmadan önce, TypeScript'teki namespace'lerin ve modüllerin temel kavramlarını anlamak çok önemlidir. Her ikisi de kod organizasyonu için mekanizmalar sağlasa da, kapsamları ve kullanımları açısından önemli ölçüde farklılık gösterirler.

Namespace'ler (Dahili Modüller)

Namespace'ler, ilgili kodları bir araya getirmek için TypeScript'e özgü bir yapıdır. Temel olarak fonksiyonlarınız, sınıflarınız, arayüzleriniz ve değişkenleriniz için isimlendirilmiş kaplar oluştururlar. Namespace'ler öncelikli olarak tek bir TypeScript projesi içindeki dahili kod organizasyonu için kullanılır. Ancak, ES modüllerinin yükselişiyle birlikte, eski kod tabanlarıyla uyumluluk veya belirli küresel genişletme senaryoları gerekmedikçe, yeni projeler için namespace'ler genellikle daha az tercih edilir.

Örnek:


namespace Geometry {
  export interface Shape {
    getArea(): number;
  }

  export class Circle implements Shape {
    constructor(public radius: number) {}

    getArea(): number {
      return Math.PI * this.radius * this.radius;
    }
  }
}

const myCircle = new Geometry.Circle(5);
console.log(myCircle.getArea()); // Output: 78.53981633974483

Modüller (Harici Modüller)

Modüller ise, ES modülleri (ECMAScript modülleri) ve CommonJS tarafından tanımlanan, kod organize etmenin standartlaştırılmış bir yoludur. Modüllerin kendi kapsamları vardır ve değerleri açıkça içeri ve dışarı aktarırlar, bu da onları yeniden kullanılabilir bileşenler ve kütüphaneler oluşturmak için ideal hale getirir. ES modülleri, modern JavaScript ve TypeScript geliştirmede standarttır.

Örnek:


// circle.ts
export interface Shape {
  getArea(): number;
}

export class Circle implements Shape {
  constructor(public radius: number) {}

  getArea(): number {
    return Math.PI * this.radius * this.radius;
  }
}

// app.ts
import { Circle } from './circle';

const myCircle = new Circle(5);
console.log(myCircle.getArea());

Namespace Birleştirmenin Gücü

Namespace birleştirme, aynı namespace adına sahip birden fazla kod bloğu tanımlamanıza olanak tanır. TypeScript, bu bildirimleri derleme zamanında akıllıca tek bir namespace altında birleştirir. Bu yetenek şu durumlar için paha biçilmezdir:

Namespace Birleştirme ile Gelişmiş Modül Bildirim Desenleri

TypeScript projelerinizde namespace birleştirmeyi kullanmak için bazı gelişmiş desenleri inceleyelim.

1. Ortam Bildirimleri ile Mevcut Kütüphaneleri Genişletme

Namespace birleştirmenin en yaygın kullanım durumlarından biri, mevcut JavaScript kütüphanelerini TypeScript tür tanımlarıyla genişletmektir. Resmi TypeScript desteği olmayan `my-library` adında bir JavaScript kütüphanesi kullandığınızı hayal edin. Bu kütüphane için türleri tanımlamak üzere bir ortam bildirim dosyası (örneğin, `my-library.d.ts`) oluşturabilirsiniz.

Örnek:


// my-library.d.ts
declare namespace MyLibrary {
  interface Options {
    apiKey: string;
    timeout?: number;
  }

  function initialize(options: Options): void;
  function fetchData(endpoint: string): Promise;
}

Artık, `MyLibrary` namespace'ini TypeScript kodunuzda tür güvenliği ile kullanabilirsiniz:


// app.ts
MyLibrary.initialize({
  apiKey: 'YOUR_API_KEY',
  timeout: 5000,
});

MyLibrary.fetchData('/api/data')
  .then(data => {
    console.log(data);
  });

Daha sonra `MyLibrary` tür tanımlarına daha fazla işlevsellik eklemeniz gerekirse, basitçe başka bir `my-library.d.ts` dosyası oluşturabilir veya mevcut olana ekleme yapabilirsiniz:


// my-library.d.ts

declare namespace MyLibrary {
  interface Options {
    apiKey: string;
    timeout?: number;
  }

  function initialize(options: Options): void;
  function fetchData(endpoint: string): Promise;

  // MyLibrary namespace'ine yeni bir fonksiyon ekleyin
  function processData(data: any): any;
}

TypeScript bu bildirimleri otomatik olarak birleştirecek ve yeni `processData` fonksiyonunu kullanmanıza olanak tanıyacaktır.

2. Küresel Nesneleri Genişletme

Bazen, `String`, `Number` veya `Array` gibi mevcut küresel nesnelere özellikler veya metotlar eklemek isteyebilirsiniz. Namespace birleştirme, bunu güvenli bir şekilde ve tür denetimiyle yapmanıza olanak tanır.

Örnek:


// string.extensions.d.ts
declare global {
  interface String {
    reverse(): string;
  }
}

String.prototype.reverse = function() {
  return this.split('').reverse().join('');
};

console.log('hello'.reverse()); // Output: olleh

Bu örnekte, `String` prototipine bir `reverse` metodu ekliyoruz. `declare global` sözdizimi, TypeScript'e küresel bir nesneyi değiştirdiğimizi söyler. Bunun mümkün olmasına rağmen, küresel nesneleri genişletmenin bazen diğer kütüphanelerle veya gelecekteki JavaScript standartlarıyla çakışmalara yol açabileceğini unutmamak önemlidir. Bu tekniği akıllıca kullanın.

Uluslararasılaştırma Hususları: Küresel nesneleri, özellikle de dizeleri veya sayıları işleyen metotlarla genişletirken, uluslararasılaştırmaya dikkat edin. Yukarıdaki `reverse` fonksiyonu temel ASCII dizeleri için çalışır, ancak karmaşık karakter setlerine veya sağdan sola yazım yönüne sahip diller için uygun olmayabilir. Yerel ayarlara duyarlı dize işleme için `Intl` gibi kütüphaneleri kullanmayı düşünün.

3. Büyük Namespace'leri Modülerleştirme

Büyük ve karmaşık namespace'lerle çalışırken, bunları daha küçük, daha yönetilebilir dosyalara bölmek faydalıdır. Namespace birleştirme bunu başarmayı kolaylaştırır.

Örnek:


// geometry.ts
namespace Geometry {
  export interface Shape {
    getArea(): number;
  }
}

// circle.ts
namespace Geometry {
  export class Circle implements Shape {
    constructor(public radius: number) {}

    getArea(): number {
      return Math.PI * this.radius * this.radius;
    }
  }
}

// rectangle.ts
namespace Geometry {
  export class Rectangle implements Shape {
    constructor(public width: number, public height: number) {}

    getArea(): number {
      return this.width * this.height;
    }
  }
}

// app.ts
/// 
/// 
/// 

const myCircle = new Geometry.Circle(5);
const myRectangle = new Geometry.Rectangle(10, 5);

console.log(myCircle.getArea()); // Output: 78.53981633974483
console.log(myRectangle.getArea()); // Output: 50

Bu örnekte, `Geometry` namespace'ini üç dosyaya ayırdık: `geometry.ts`, `circle.ts` ve `rectangle.ts`. Her dosya `Geometry` namespace'ine katkıda bulunur ve TypeScript bunları bir araya getirir. `/// ` direktiflerinin kullanımına dikkat edin. Bunlar çalışsa da, eski bir yaklaşımdır ve namespace kullanırken bile modern TypeScript projelerinde genellikle ES modüllerini kullanmak tercih edilir.

Modern Modül Yaklaşımı (Tercih Edilen):


// geometry.ts
export namespace Geometry {
  export interface Shape {
    getArea(): number;
  }
}

// circle.ts
import { Geometry } from './geometry';

export namespace Geometry {
  export class Circle implements Shape {
    constructor(public radius: number) {}

    getArea(): number {
      return Math.PI * this.radius * this.radius;
    }
  }
}

// rectangle.ts
import { Geometry } from './geometry';

export namespace Geometry {
  export class Rectangle implements Shape {
    constructor(public width: number, public height: number) {}

    getArea(): number {
      return this.width * this.height;
    }
  }
}

// app.ts
import { Geometry } from './geometry';
const myCircle = new Geometry.Circle(5);
const myRectangle = new Geometry.Rectangle(10, 5);

console.log(myCircle.getArea());
console.log(myRectangle.getArea());

Bu yaklaşım, namespace'lerle birlikte ES modüllerini kullanarak daha iyi modülerlik ve modern JavaScript araçlarıyla uyumluluk sağlar.

4. Arayüz Genişletme ile Namespace Birleştirme Kullanımı

Namespace birleştirme, mevcut türlerin yeteneklerini genişletmek için genellikle arayüz genişletme ile birleştirilir. Bu, diğer kütüphanelerde veya modüllerde tanımlanan arayüzlere yeni özellikler veya metotlar eklemenize olanak tanır.

Örnek:


// user.ts
interface User {
  id: number;
  name: string;
}

// user.extensions.ts
namespace User {
  export interface User {
    email: string;
  }
}

// app.ts
import { User } from './user'; // user.ts dosyasının User arayüzünü dışa aktardığını varsayarsak
import './user.extensions'; // Yan etki için içe aktarma: User arayüzünü genişlet

const myUser: User = {
  id: 123,
  name: 'John Doe',
  email: 'john.doe@example.com',
};

console.log(myUser.name);
console.log(myUser.email);

Bu örnekte, namespace birleştirme ve arayüz genişletme kullanarak `User` arayüzüne bir `email` özelliği ekliyoruz. `user.extensions.ts` dosyası `User` arayüzünü genişletir. `app.ts` dosyasındaki `./user.extensions` içe aktarımına dikkat edin. Bu içe aktarma yalnızca `User` arayüzünü genişletme yan etkisi içindir. Bu içe aktarma olmadan, genişletme etkili olmazdı.

Namespace Birleştirme için En İyi Uygulamalar

Namespace birleştirme güçlü bir özellik olsa da, olası sorunları önlemek için akıllıca kullanmak ve en iyi uygulamaları takip etmek esastır:

Küresel Hususlar

Küresel bir kitle için uygulamalar geliştirirken, namespace birleştirmeyi kullanırken aşağıdaki hususları göz önünde bulundurun:

`Intl` (Uluslararasılaştırma API'si) ile yerelleştirme örneği:


// number.extensions.d.ts
declare global {
  interface Number {
    toCurrencyString(locale: string, currency: string): string;
  }
}

Number.prototype.toCurrencyString = function(locale: string, currency: string) {
  return new Intl.NumberFormat(locale, {
    style: 'currency',
    currency: currency,
  }).format(this);
};

const price = 1234.56;

console.log(price.toCurrencyString('en-US', 'USD')); // Output: $1,234.56
console.log(price.toCurrencyString('de-DE', 'EUR')); // Output: 1.234,56 €
console.log(price.toCurrencyString('ja-JP', 'JPY')); // Output: ¥1,235

Bu örnek, sayıları farklı yerel ayarlara ve para birimlerine göre biçimlendirmenize olanak tanıyan `Intl.NumberFormat` API'sini kullanarak `Number` prototipine bir `toCurrencyString` metodunun nasıl ekleneceğini gösterir.

Sonuç

TypeScript namespace birleştirme, kütüphaneleri genişletmek, kodu modülerleştirmek ve karmaşık tür tanımlarını yönetmek için güçlü bir araçtır. Bu kılavuzda özetlenen gelişmiş desenleri ve en iyi uygulamaları anlayarak, daha temiz, daha sürdürülebilir ve daha ölçeklenebilir TypeScript kodu yazmak için namespace birleştirmeden yararlanabilirsiniz. Ancak, yeni projeler için genellikle ES modüllerinin tercih edilen bir yaklaşım olduğunu ve namespace birleştirmenin stratejik ve akıllıca kullanılması gerektiğini unutmayın. Uygulamalarınızın dünya çapındaki kullanıcılar tarafından erişilebilir ve kullanılabilir olmasını sağlamak için, özellikle yerelleştirme, karakter kodlaması ve kültürel geleneklerle uğraşırken kodunuzun küresel etkilerini daima göz önünde bulundurun.